/*
 *  Copyright 2011 yuxinlei.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package com.hudson.plugin.result.collector.server.datastore.internal.dao.impl;

import com.hudson.plugin.result.collector.server.datastore.dao.ViewsEntityJpaController;
import com.hudson.plugin.result.collector.server.datastore.dao.exceptions.NonexistentEntityException;
import com.hudson.plugin.result.collector.server.datastore.dao.exceptions.PreexistingEntityException;
import com.hudson.plugin.result.collector.server.datastore.internal.entity.*;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author yuxinlei
 */
public class ViewsEntityJpaControllerImpl implements ViewsEntityJpaController {

    public ViewsEntityJpaControllerImpl() {
        emf = Persistence.createEntityManagerFactory("reportdb");
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(ViewsEntity viewsEntity) throws PreexistingEntityException, Exception {
        if (viewsEntity.getProjectsesById() == null) {
            viewsEntity.setProjectsesById(new ArrayList<ProjectsEntity>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            HudsonsEntity hudsonsByHudsonId = viewsEntity.getHudsonsByHudsonId();
            if (hudsonsByHudsonId != null) {
                hudsonsByHudsonId = em.getReference(hudsonsByHudsonId.getClass(), hudsonsByHudsonId.getId());
                viewsEntity.setHudsonsByHudsonId(hudsonsByHudsonId);
            }
            Collection<ProjectsEntity> attachedProjectsesById = new ArrayList<ProjectsEntity>();
            for (ProjectsEntity projectsesByIdProjectsEntityToAttach : viewsEntity.getProjectsesById()) {
                projectsesByIdProjectsEntityToAttach = em.getReference(projectsesByIdProjectsEntityToAttach.getClass(), projectsesByIdProjectsEntityToAttach.getId());
                attachedProjectsesById.add(projectsesByIdProjectsEntityToAttach);
            }
            viewsEntity.setProjectsesById(attachedProjectsesById);
            em.persist(viewsEntity);
            if (hudsonsByHudsonId != null) {
                hudsonsByHudsonId.getViewsesById().add(viewsEntity);
                hudsonsByHudsonId = em.merge(hudsonsByHudsonId);
            }
            for (ProjectsEntity projectsesByIdProjectsEntity : viewsEntity.getProjectsesById()) {
                ViewsEntity oldViewsByViewIdOfProjectsesByIdProjectsEntity = projectsesByIdProjectsEntity.getViewsByViewId();
                projectsesByIdProjectsEntity.setViewsByViewId(viewsEntity);
                projectsesByIdProjectsEntity = em.merge(projectsesByIdProjectsEntity);
                if (oldViewsByViewIdOfProjectsesByIdProjectsEntity != null) {
                    oldViewsByViewIdOfProjectsesByIdProjectsEntity.getProjectsesById().remove(projectsesByIdProjectsEntity);
                    oldViewsByViewIdOfProjectsesByIdProjectsEntity = em.merge(oldViewsByViewIdOfProjectsesByIdProjectsEntity);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findViewsEntity(viewsEntity.getId()) != null) {
                throw new PreexistingEntityException("ViewsEntity " + viewsEntity + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(ViewsEntity viewsEntity) throws NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            ViewsEntity persistentViewsEntity = em.find(ViewsEntity.class, viewsEntity.getId());
            HudsonsEntity hudsonsByHudsonIdOld = persistentViewsEntity.getHudsonsByHudsonId();
            HudsonsEntity hudsonsByHudsonIdNew = viewsEntity.getHudsonsByHudsonId();
            Collection<ProjectsEntity> projectsesByIdOld = persistentViewsEntity.getProjectsesById();
            Collection<ProjectsEntity> projectsesByIdNew = viewsEntity.getProjectsesById();
            if (hudsonsByHudsonIdNew != null) {
                hudsonsByHudsonIdNew = em.getReference(hudsonsByHudsonIdNew.getClass(), hudsonsByHudsonIdNew.getId());
                viewsEntity.setHudsonsByHudsonId(hudsonsByHudsonIdNew);
            }
            Collection<ProjectsEntity> attachedProjectsesByIdNew = new ArrayList<ProjectsEntity>();
            for (ProjectsEntity projectsesByIdNewProjectsEntityToAttach : projectsesByIdNew) {
                projectsesByIdNewProjectsEntityToAttach = em.getReference(projectsesByIdNewProjectsEntityToAttach.getClass(), projectsesByIdNewProjectsEntityToAttach.getId());
                attachedProjectsesByIdNew.add(projectsesByIdNewProjectsEntityToAttach);
            }
            projectsesByIdNew = attachedProjectsesByIdNew;
            viewsEntity.setProjectsesById(projectsesByIdNew);
            viewsEntity = em.merge(viewsEntity);
            if (hudsonsByHudsonIdOld != null && !hudsonsByHudsonIdOld.equals(hudsonsByHudsonIdNew)) {
                hudsonsByHudsonIdOld.getViewsesById().remove(viewsEntity);
                hudsonsByHudsonIdOld = em.merge(hudsonsByHudsonIdOld);
            }
            if (hudsonsByHudsonIdNew != null && !hudsonsByHudsonIdNew.equals(hudsonsByHudsonIdOld)) {
                hudsonsByHudsonIdNew.getViewsesById().add(viewsEntity);
                hudsonsByHudsonIdNew = em.merge(hudsonsByHudsonIdNew);
            }
            for (ProjectsEntity projectsesByIdOldProjectsEntity : projectsesByIdOld) {
                if (!projectsesByIdNew.contains(projectsesByIdOldProjectsEntity)) {
                    projectsesByIdOldProjectsEntity.setViewsByViewId(null);
                    projectsesByIdOldProjectsEntity = em.merge(projectsesByIdOldProjectsEntity);
                }
            }
            for (ProjectsEntity projectsesByIdNewProjectsEntity : projectsesByIdNew) {
                if (!projectsesByIdOld.contains(projectsesByIdNewProjectsEntity)) {
                    ViewsEntity oldViewsByViewIdOfProjectsesByIdNewProjectsEntity = projectsesByIdNewProjectsEntity.getViewsByViewId();
                    projectsesByIdNewProjectsEntity.setViewsByViewId(viewsEntity);
                    projectsesByIdNewProjectsEntity = em.merge(projectsesByIdNewProjectsEntity);
                    if (oldViewsByViewIdOfProjectsesByIdNewProjectsEntity != null && !oldViewsByViewIdOfProjectsesByIdNewProjectsEntity.equals(viewsEntity)) {
                        oldViewsByViewIdOfProjectsesByIdNewProjectsEntity.getProjectsesById().remove(projectsesByIdNewProjectsEntity);
                        oldViewsByViewIdOfProjectsesByIdNewProjectsEntity = em.merge(oldViewsByViewIdOfProjectsesByIdNewProjectsEntity);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                int id = viewsEntity.getId();
                if (findViewsEntity(id) == null) {
                    throw new NonexistentEntityException("The viewsEntity with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(int id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            ViewsEntity viewsEntity;
            try {
                viewsEntity = em.getReference(ViewsEntity.class, id);
                viewsEntity.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The viewsEntity with id " + id + " no longer exists.", enfe);
            }
            HudsonsEntity hudsonsByHudsonId = viewsEntity.getHudsonsByHudsonId();
            if (hudsonsByHudsonId != null) {
                hudsonsByHudsonId.getViewsesById().remove(viewsEntity);
                hudsonsByHudsonId = em.merge(hudsonsByHudsonId);
            }
            Collection<ProjectsEntity> projectsesById = viewsEntity.getProjectsesById();
            for (ProjectsEntity projectsesByIdProjectsEntity : projectsesById) {
                projectsesByIdProjectsEntity.setViewsByViewId(null);
                projectsesByIdProjectsEntity = em.merge(projectsesByIdProjectsEntity);
            }
            em.remove(viewsEntity);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public ViewsEntity findViewsEntity(int id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(ViewsEntity.class, id);
        } finally {
            em.close();
        }
    }

    public List<Integer> findViewsEntityByModuleAndIcafeProject(String moduleName, String icafeProjectName) {
        EntityManager em = getEntityManager();
        try {
            Query query = em.createNativeQuery(
                    "select v.id from views v where v.icafe_project = :icafeProject and v.module = :module"  );
            query.setParameter("icafeProject", icafeProjectName.trim());
            query.setParameter("module", moduleName.trim());
            List<Integer> viewids = query.getResultList();
            return viewids;
        } finally {
            em.close();
        }
    }

public List<ViewsEntity> findViewsEntityEntities() {
        return findViewsEntityEntities(true, -1, -1);
    }

    public List<ViewsEntity> findViewsEntityEntitiesWithInterval(boolean isAverage, int resultsInterval, int firstResult) {
        return findViewsEntityEntities(true, -1, -1);
    }

    public List<ViewsEntity> findViewsEntityEntities(int maxResults, int firstResult) {
        return findViewsEntityEntities(false, maxResults, firstResult);
    }

    private List<ViewsEntity> findViewsEntityEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(ViewsEntity.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }



    public int getViewsEntityCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<ViewsEntity> rt = cq.from(ViewsEntity.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }


}
